import { mouse } from '@/utils/keyboardAndMouse'
import { dropEventCenter } from './dropEventCenter'
import { DROPPABLE_ACCEPTS_TYPE_KEY, DROPPABLE_ID_KEY, IDragData } from './interfaces'

const canDrop = (data: IDragData, el?: HTMLElement | null) => {
    if (!el) return false
    // 本来是用className来判断的，但是className在update后会丢失，所以用dataset来判断
    if (!el.dataset[DROPPABLE_ID_KEY]) return false
    const acceptTypes = el.dataset[DROPPABLE_ACCEPTS_TYPE_KEY]
    if (!acceptTypes) return true
    if (!acceptTypes.split(',').includes(data.type)) return false
    return true
}

/** 找到最近的可以被拖放的容器 */
const findNearestDroppable = (data: IDragData, el?: HTMLElement | null) => {
    let target = el
    while (target && !canDrop(data, target)) {
        target = target?.parentElement
    }
    return target
}

export interface IUseDragOptions {
    /** 拖拽开始时触发 */
    onDragStart?: (e?: MouseEvent) => void
    /** 拖拽结束时触发 */
    onDragEnd?: (e?: MouseEvent) => void
    /** 拖拽进入目标时触发 */
    onDragMove?: (e?: MouseEvent) => void
}

export const useDrag = <DragData = any>(data: IDragData<DragData>, options: IUseDragOptions = {}) => {
    let droppableTarget: HTMLElement | null | undefined = null

    // 处理正在拖拽事件，mousemove事件
    const dragging = (e: MouseEvent) => {
        // console.log('dragging')
        options.onDragMove?.(e)

        // console.log(e.target)
        const target = findNearestDroppable(data, e.target as HTMLElement)

        if (droppableTarget === target) return

        const oldDroppableTarget = droppableTarget
        droppableTarget = target

        if (oldDroppableTarget) {
            const id = oldDroppableTarget.dataset[DROPPABLE_ID_KEY]
            dropEventCenter.emit(id, 'leave', data, oldDroppableTarget)
        }
        if (droppableTarget) {
            const id = droppableTarget.dataset[DROPPABLE_ID_KEY]
            dropEventCenter.emit(id, 'enter', data, droppableTarget)
        }
    }

    // 拖拽结束
    const dragEnd = (e: MouseEvent) => {
        options.onDragEnd?.(e)

        // 清空鼠标数据
        mouse.storage.delete('dragging')

        // 移除事件
        mouse.off('mousemove', dragging)

        // 设置鼠标为非正在拖拽
        mouse.isDragging = false

        // 触发drop事件
        if (droppableTarget) {
            const id = droppableTarget.dataset[DROPPABLE_ID_KEY]
            dropEventCenter.emit(id, 'drop', data, droppableTarget)
        }
    }

    /**
     * mousedown事件处理器
     */
    const dragStart = (e?: MouseEvent) => {
        // 把这些数据存储起来
        // mouse.storage.set(DRAGGING_DATA_KEY, data)
        // 注册mousemove
        mouse.on('mousemove', dragging)
        // 注册mouseup
        mouse.once('mouseup', dragEnd)
        // 设置鼠标为正在拖拽
        mouse.isDragging = true

        // 触发一下用户的回调
        options.onDragStart?.(e)
    }

    return { dragStart }
}
